To make MongoDB database manipulation easy, we can use the Mongoose NPM package to make working with MongoDB databases easier.
In this article, we’ll look at how to use Mongoose to manipulate our MongoDB database.
Populate Virtuals
We can control how 2 models are joined together.
For example, we can write:
async function run() {
const { createConnection, Types, Schema } = require('mongoose');
const db = createConnection('mongodb://localhost:27017/test');
const PersonSchema = new Schema({
name: String,
band: String
});
const BandSchema = new Schema({
name: String
});
BandSchema.virtual('members', {
ref: 'Person',
localField: 'name',
foreignField: 'band',
justOne: false,
options: { sort: { name: -1 }, limit: 5 }
});
const Person = db.model('Person', PersonSchema);
const Band = db.model('Band', BandSchema);
const person = new Person({ name: 'james', band: 'superband' });
await person.save();
const band = new Band({ name: 'superband' });
await band.save();
const bands = await Band.find({}).populate('members').exec();
console.log(bands[0].members);
}
run();
We create the PersonSchema
as usual, but the BandSchema
is different.
We call the virtual
method with the join field call members
to get the persons with the band
name set to a given name.
The ref
property is the name of the model we want to join.
localField
is the field of the BandSchema
that we want to join with PersonSchema
.
The foreignField
is the field of PersonSchema
that we want to join with the BandSchema
.
justOne
means we only return the first entry of the join.
options
has the options for querying.
Virtuals aren’t included in the toJSON()
output by default.
If we want populate virtual to show when using functions that rely on JSON.stringify()
, then add the virtuals
option and set it to true
.
For example, we can write:
async function run() {
const { createConnection, Types, Schema } = require('mongoose');
const db = createConnection('mongodb://localhost:27017/test');
const PersonSchema = new Schema({
name: String,
band: String
});
const BandSchema = new Schema({
name: String
}, { toJSON: { virtuals: true } });
BandSchema.virtual('members', {
ref: 'Person',
localField: 'name',
foreignField: 'band',
justOne: false,
options: { sort: { name: -1 }, limit: 5 }
});
const Person = db.model('Person', PersonSchema);
const Band = db.model('Band', BandSchema);
const person = new Person({ name: 'james', band: 'superband' });
await person.save();
const band = new Band({ name: 'superband' });
await band.save();
const bands = await Band.find({}).populate('members').exec();
console.log(bands[0].members);
}
run();
to add the virtuals
option to the BandSchema
.
If we use populate projections, then foreignField
should be included in the projection:
async function run() {
const { createConnection, Types, Schema } = require('mongoose');
const db = createConnection('mongodb://localhost:27017/test');
const PersonSchema = new Schema({
name: String,
band: String
});
const BandSchema = new Schema({
name: String
}, { toJSON: { virtuals: true } });
BandSchema.virtual('members', {
ref: 'Person',
localField: 'name',
foreignField: 'band',
justOne: false,
options: { sort: { name: -1 }, limit: 5 }
});
const Person = db.model('Person', PersonSchema);
const Band = db.model('Band', BandSchema);
const person = new Person({ name: 'james', band: 'superband' });
await person.save();
const band = new Band({ name: 'superband' });
await band.save();
const bands = await Band.find({}).populate({ path: 'members', select: 'name band' }).exec();
console.log(bands[0].members);
}
run();
We call populate
with an object with the path
to get the virtual field and the select
property has a string with the field names that we want to get separated by a space.
Conclusion
We can use Mongoose populate virtual feature to join 2 models by a column other than an ID column.